package com.qianfeng.netty.http;

//
//                            _ooOoo_  
//                           o8888888o  
//                           88" . "88  
//                           (| -_- |)  
//                            O\ = /O  
//                        ____/`---'\____  
//                      .   ' \\| |// `.  
//                       / \\||| : |||// \  
//                     / _||||| -:- |||||- \  
//                       | | \\\ - /// | |  
//                     | \_| ''\---/'' | |  
//                      \ .-\__ `-` ___/-. /  
//                   ___`. .' /--.--\ `. . __  
//                ."" '< `.___\_<|>_/___.' >'"".  
//               | | : `- \`.;`\ _ /`;.`/ - ` : | |  
//                 \ \ `-. \_ __\ /__ _/ .-` / /  
//         ======`-.____`-.___\_____/___.-`____.-'======  
//                            `=---='  
//  
//         .............................................  
//                  佛祖镇楼                  BUG辟易  
//          佛曰:  
//                  写字楼里写字间，写字间里程序员；  
//                  程序人员写程序，又拿程序换酒钱。  
//                  酒醒只在网上坐，酒醉还来网下眠；  
//                  酒醉酒醒日复日，网上网下年复年。  
//                  但愿老死电脑间，不愿鞠躬老板前；  
//                  奔驰宝马贵者趣，公交自行程序员。  
//                  别人笑我忒疯癫，我笑自己命太贱；  
//  


import com.fasterxml.jackson.databind.ObjectMapper;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by Jackiechan on 2022/7/6 11:03
 * 我们前面设置的handler会将请求转成http类型,变成一个httpobject对象给我们传递过来
 * @author Jackiechan
 * @version 1.0
 * @since 1.0
 */
public class MyHttpHandler extends SimpleChannelInboundHandler<HttpObject> {

    private ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 收到了http请求
     * @param ctx           the {@link ChannelHandlerContext} which this {@link SimpleChannelInboundHandler}
     *                      belongs to
     * @param msg           the message to handle
     * @throws Exception
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
        System.err.println("MyHttpHandler中的方法channelRead0 执行了");

        //我们给客户端返回一个数据,我们需要返回一个http类型的数据
        //我们要返回的内容
//        ByteBuf byteBuf = Unpooled.copiedBuffer("今天下雨吗?".getBytes(StandardCharsets.UTF_8));
//        //参数1, http的协议版本,参数2 http的响应的状态码, 参数3,我们要返回的数据
//        DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, byteBuf);
//        //我们还可以返回一些响应头
//        response.headers().add("laowangdetou", "xiangpiqiu").set(HttpHeaderNames.CONTENT_TYPE, "text/html;charset=utf-8");
//        //把http响应写出去
//        ctx.writeAndFlush(response);
        //实际开发中我们需要根据不同的请求地址处理不同的操作
        //比如我们模拟一个简单的springmvc的感觉, 一个get请求传递几个参数过来,然后到达我们的controller,返回结果
        if (msg instanceof HttpRequest) {

            //获取到请求的地址,这个地址包括了get中传递的参数 ?以及之后的东西
            String uri = ((HttpRequest) msg).uri();
            //path是我们的请求地址,暂时和用户请求的是一样,但是如果有?就不一样了,我们需要裁剪,将地址和参数分开
            String path = uri;
            //保存参数的map
            Map paramMap = new HashMap();
            if (uri.contains("?")) {
                //代表地址中包含参数,我们需要把地址取出来
                path = path.substring(0, path.indexOf("?"));
                //把参数取出来,不包括问号
                String queryString = uri.substring(uri.indexOf("?") + 1);
               // System.err.println(path);
             //   System.err.println(queryString);
                //将参数以&分割得到 多个key=value的字符串
                String[] allParams = queryString.split("&");
                for (String allParam : allParams) {
                    //得到每个参数的key 和value
                    String[] split = allParam.split("=");
                    //保存到map中
                    paramMap.put(split[0], split[1]);
                }
            }
            System.err.println(paramMap);
            //看看这个地址对应什么方法
            Method method = RequestUtil.url2Method.get(path);
            if (method != null) {
                Object controller = RequestUtil.url2Object.get(path);
                //说明这个地址有处理的方式
                //拿到这个方法,反射调用这个方法
                //我们发现我们遇到一个最严重的问题,参数问题,method我们可以反射找到,对象可以反射创建,但是参数有顺序问题
                //我们首先得知道我们这个方法的参数的顺序,然后把传递过来的参数按照顺序拍好,然后传递过来,还不能多传,也不能少传,个数必须匹配
                // 获取到方法需要的参数列表
                Parameter[] parameters = method.getParameters();
                //我们需要传递参数,参数的长度必须和方法需要的一样,所以方法的参数有多长,我们就创建一个多长的数组
                Object[] values = new Object[parameters.length];
                //需要知道它需要的每一个参数的名字
                for (int i = 0; i < parameters.length; i++) {
                    //得到每个位置的参数
                    Parameter parameter = parameters[i];
                    //得到每个参数的名字
                    String name = parameter.getName();
                    //当前实际参数数组中对位位置数据设置为传递id值
                    values[i] = paramMap.get(name);
                }
                //利用刚才反射拼接的参数,加上我们的对象,执行方法获取返回值
                Object result = method.invoke(controller,values);
                System.err.println("返回结果是:"+result);
                String jsonResult = objectMapper.writeValueAsString(result);
                //返回数据的bytebuf
                ByteBuf byteBuf = Unpooled.copiedBuffer(jsonResult.getBytes(StandardCharsets.UTF_8));
                //创建一个响应对象
                DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, byteBuf);
                response.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json;charset=utf-8");
                //返回数据
                ctx.writeAndFlush(response);
                ctx.close();
            }else{
                //返回一个404
            }

        }
    }
}
